﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Collections;
using Mandelbrot_Florian.Controller;
using Mandelbrot_Florian.Model;
using System.IO;
using System.Threading.Tasks;
using System.Threading;

namespace Mandelbrot_Florian.Service
{
    public class MandelbrotService
    {
        private MainController _controller;
        private Thread mandelThread;
        private object _locked = new object();

        public MandelbrotService(MainController controller)
        {
            _controller = controller;
        }

        private static double GetIntigralX(MandelbrotModel model)
        {
            return (model.Fx - model.Sx) / model.Img.Width;
        }
        private static double GetIntigralY(MandelbrotModel model)
        {
            return (model.Fy - model.Sy) / model.Img.Height;
        }
        public MandelbrotModel Zoom(Rectangle selection)
        {
            MandelbrotModel currentModel = _controller.CurrentModel;
            MandelbrotModel zoomingModel = new MandelbrotModel();

            if (selection != Rectangle.Empty && selection.Width > 0 && selection.Height > 0)
            {
                double intigralX = GetIntigralX(currentModel);
                double intigralY = GetIntigralY(currentModel);
                zoomingModel.Sx = currentModel.Sx + (selection.Left * intigralX);
                zoomingModel.Sy = currentModel.Sy + (selection.Top * intigralY);
                zoomingModel.Fx = currentModel.Sx + (selection.Right * intigralX);
                zoomingModel.Fy = currentModel.Sy + (selection.Bottom * intigralY);

                zoomingModel.Img = currentModel.Img;
                zoomingModel.MaxIteration = currentModel.MaxIteration;
                zoomingModel.ColorName = currentModel.ColorName;
                zoomingModel.Colors = currentModel.Colors;
            }

            return zoomingModel;
        }

        public void DrawMandel()
        {
            MandelbrotModel model = _controller.CurrentModel;
            double intigralX = GetIntigralX(model);
            double intigralY = GetIntigralY(model);
            Bitmap b = new Bitmap(model.Img);
            int width = model.Img.Width;
            int height = model.Img.Height;

            _controller.InitProgressBar();
            model.Timer.Reset();
            model.Timer.Start();

            for (int s = 1; s < width; s++)
            {
                for (int z = 1; z < height; z++)
                {
                    double x = model.Sx + (s * intigralX);
                    double y = model.Sy + (z * intigralY);
                    double x1 = 0;
                    double y1 = 0;
                    int looper = 0;
                    while (looper < model.MaxIteration && (x1 * x1) + (y1 * y1) < 4)
                    {
                        looper++;
                        double xx = (x1 * x1) - (y1 * y1) + x;
                        y1 = 2 * x1 * y1 + y;
                        x1 = xx;
                    }
                    //Draw color
                    double perc = looper / (double)model.MaxIteration;
                    int val = (int)(perc * 255);
                    b.SetPixel(s, z, model.Colors[val]);

                }
                _controller.UpdateProgress();
            }

            model.Timer.Stop();
            model.Img = b;
            _controller.EndingDrawMandel(model);

            //If DrawMandelByThread
            if (mandelThread != null && mandelThread.IsAlive)
                mandelThread.Abort();
        }
        public void DrawMandelByThread()
        {
            mandelThread = new Thread(new ThreadStart(DrawMandel));
            mandelThread.Start();
            //mandelThread.Join();
        }
        public void DrawMandelByTask()
        {
            MandelbrotModel model = _controller.CurrentModel;
            double intigralX = GetIntigralX(model);
            double intigralY = GetIntigralY(model);
            Bitmap b = new Bitmap(model.Img);
            int width = model.Img.Width;
            int height = model.Img.Height;

            _controller.InitProgressBar();
            model.Timer.Reset();
            model.Timer.Start();


            Parallel.For(1, width, s =>
            {
                for (int z = 1; z < height; z++)
                {
                    //Parallel.For(1, height, z =>
                    //{
                    double x = model.Sx + (s * intigralX);
                    double y = model.Sy + (z * intigralY);
                    double x1 = 0;
                    double y1 = 0;
                    int looper = 0;
                    while (looper < model.MaxIteration && (x1 * x1) + (y1 * y1) < 4)
                    {
                        looper++;
                        double xx = (x1 * x1) - (y1 * y1) + x;
                        y1 = 2 * x1 * y1 + y;
                        x1 = xx;
                    }
                    //Draw color
                    double perc = looper / (double)model.MaxIteration;
                    int val = (int)(perc * 255);
                    lock (_locked)
                        b.SetPixel(s, z, model.Colors[val]);

                    //}); // Parallel.For
                }
                //_controller.UpdateProgress();
            }); // Parallel.For

            model.Timer.Stop();
            model.Img = b;
            _controller.EndingDrawMandel(model);
        }
        public void DrawMandelByTask2()
        {
            MandelbrotModel model = _controller.CurrentModel;
            double intigralX = GetIntigralX(model);
            double intigralY = GetIntigralY(model);
            Bitmap b = new Bitmap(model.Img);
            int width = model.Img.Width;
            int height = model.Img.Height;

            _controller.InitProgressBar();
            model.Timer.Reset();
            model.Timer.Start();


            Parallel.For(1, width, s =>
            {
                //for (int z = 1; z < height; z++)
                //{
                Parallel.For(1, height, z =>
                {
                    double x = model.Sx + (s * intigralX);
                    double y = model.Sy + (z * intigralY);
                    double x1 = 0;
                    double y1 = 0;
                    int looper = 0;
                    while (looper < model.MaxIteration && (x1 * x1) + (y1 * y1) < 4)
                    {
                        looper++;
                        double xx = (x1 * x1) - (y1 * y1) + x;
                        y1 = 2 * x1 * y1 + y;
                        x1 = xx;
                    }
                    //Draw color
                    double perc = looper / (double)model.MaxIteration;
                    int val = (int)(perc * 255);
                    lock (_locked)
                        b.SetPixel(s, z, model.Colors[val]);

                }); // Parallel.For
                //}
                //_controller.UpdateProgress();
            }); // Parallel.For

            model.Timer.Stop();
            model.Img = b;
            _controller.EndingDrawMandel(model);
        }

        public static List<string> GetColorsName()
        {
            try
            {
                List<string> listNames = new List<string>();
                string[] ColMaps = Directory.GetFiles(Model.Parameters.colorsPath, Model.Parameters.colorsPattern);
                foreach (string path in ColMaps)
                {
                    string extentionName = path.Split('\\').Last();//GreenEdge.ColorMap
                    string name = extentionName.Split('.').First();//GreenEdge
                    listNames.Add(name);
                }
                return listNames;
            }
            catch (Exception ex)
            {
                throw new Exception("Directory not valide", ex);
            }
        }
        public static Color[] GetColors(string colorName)
        {
            try
            {
                string Path = Parameters.colorsPath + colorName + Parameters.colorsEndPath;

                Color[] c = new Color[256];
                System.IO.StreamReader sr = new System.IO.StreamReader(Path);
                ArrayList lines = new ArrayList();
                string s = sr.ReadLine();
                while (s != null)
                {
                    lines.Add(s);
                    s = sr.ReadLine();
                }
                int i = 0;
                for (i = 0; i < Math.Min(256, lines.Count); i++)
                {
                    string curC = (string)lines[i];
                    Color temp = Color.FromArgb(int.Parse(curC.Split(' ')[0]), int.Parse(curC.Split(' ')[1]), int.Parse(curC.Split(' ')[2]));
                    c[i] = temp;
                }
                for (int j = i; j < 256; j++)
                {
                    c[j] = Color.White;
                }
                return c;
            }
            catch (Exception ex)
            {
                throw new Exception("Invalid ColorMap file.", ex);
            }
        }
    }
}
